package com.jun.socket;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;


/**
 * 访问地址: ws://localhost:8080/socket/{id}
 */
@Slf4j
@Component
@ServerEndpoint("/socket/{id}")
public class CustomServiceSocket {
  private Boolean isAdmin;
  private String id;

  private static final ObjectMapper objectMapper = new ObjectMapper();

  // 存放用户的id
  private static final CopyOnWriteArraySet<String> userSet = new CopyOnWriteArraySet<>();

  // 存放管理员的id
  private static final CopyOnWriteArraySet<String> adminSet = new CopyOnWriteArraySet<>();

  // 用来存放所有在线连接用户信息
  private static final ConcurrentHashMap<String, Session> sessionPool = new ConcurrentHashMap<>();


  @OnOpen
  public void open(Session session, @PathParam("id") String id) throws JsonProcessingException {
    log.info("建立连接, id = " + id);

    // 前缀"a_"为管理员,"u_"为用户
    String prefix = id.substring(0, 2);
    this.id = id;
    this.isAdmin = ("a_".equals(prefix));
    sessionPool.put(id, session);

    if (this.isAdmin) {
      log.info("连接为管理员");
      adminSet.add(id);
    } else {
      log.info("连接为用户");
      userSet.add(id);
    }

    sendAllAdminOnline();
  }

  @OnClose
  public void close() {
    log.info("关闭连接");

    sessionPool.remove(id);

    if (isAdmin) {
      adminSet.remove(id);
    } else {
      userSet.remove(id);
    }

    sendAllAdminOnline();
  }

  @OnMessage
  public void message(String message) {
    log.info("收到的消息" + message);

    try {
      SendObj sendObj = objectMapper.readValue(message, SendObj.class);

      sendOne(sendObj.getMsg(), sendObj.getToId(), true);
    } catch (JsonProcessingException e) {
      log.info("接收的消息格式不是SendObj类型");
    }
  }

  @OnError
  public void error(Throwable error) {
    error.printStackTrace();
  }

  /**
   * 发送单点信息
   * @param msg 发送的信息
   * @param id 接收的id
   * @param isSave 是否保存
   */
  public void sendOne(String msg, String id, boolean isSave) {
    log.info("发送的消息 = " + msg + ", 到 id = " + id);
    try {
      Session session = sessionPool.get(id);

      Map<String, Object> result = new HashMap<>(2);
      result.put("msg", msg);
      result.put("isSave", isSave);
      String json = objectMapper.writeValueAsString(result);

      if (session != null && session.isOpen()) {
        session.getAsyncRemote().sendText(json);
      }
    } catch (JsonProcessingException e) {
      log.info("发送失败");
    }
  }

  /**
   * 告诉所有管理员在线人数
   */
  public void sendAllAdminOnline() {
    try {
      Map<String, Object> send = new HashMap<>();

      // 发送给用户的数据
      send.put("adminSet", adminSet);
      String sendToUser = objectMapper.writeValueAsString(send);

      // @TODO 异步
      for (String id : userSet) {
        sendOne(sendToUser, id, false);
      }

      // 发送给管理员的数据
      send.put("userSet", userSet);
      String sendToAdmin = objectMapper.writeValueAsString(send);

      // @TODO 异步
      for (String id : adminSet) {
        sendOne(sendToAdmin, id, false);
      }

    } catch (JsonProcessingException e) {
      e.printStackTrace();
    }
  }
}

  ///**
  // * 发送多个单点信息
  // * @param message 发送的信息
  // * @param ids 接收的多个id
  // * @param isSave 是否保存
  // */
  //public void sendList(String message,  List<String> ids, boolean isSave) {
  //  for (String id : ids) {
  //    sendOne(message, id, isSave);
  //  }
  //}

  ///**
  // * 广播模式
  // * @param message 发送的信息
  // */
  //public void sendAll(String message) {
  //  for (CustomServiceSocket socket : webSockets) {
  //    if (socket.session.isOpen()) {
  //      socket.session.getAsyncRemote().sendText(message);
  //    }
  //  }
  //}



@Data
class SendObj {
  private String msg;     // 发送的信息
  private String toId;    // 接收的id
}
